package dxn.nl.export.deal.netty;

import dxn.nl.file.client.model.codec.MessageCodec;
import dxn.nl.file.client.model.dto.TransferMessageDto;
import dxn.nl.file.client.model.enums.ExportMessageTypeEnum;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.timeout.IdleStateHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

public class ExportDealServer implements DisposableBean {

    private static final Logger log = LoggerFactory.getLogger(ExportDealServer.class);

    private final String applicationName;

    private final String serverHost;

    private final int serverPort;

    public Channel channel;

    private boolean running = true;

    public ExportDealServer(String applicationName,String serverHost,int serverPort)
    {
        this.applicationName = applicationName;
        this.serverHost = serverHost;
        this.serverPort = serverPort;
    }

    public String getServerUrl()
    {
        return serverHost+":"+serverPort;
    }

    EventLoopGroup eventLoopGroup = new NioEventLoopGroup(100);
    Bootstrap bootstrap = new Bootstrap();
    ChannelFuture future;

    public boolean run() {
        try {
            log.info("启动导出处理客户端任务---------");
            bootstrap.group(eventLoopGroup)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.SO_KEEPALIVE, true)
                    .remoteAddress(serverHost, serverPort)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) {
                            //socketChannel.config().setRecvByteBufAllocator(new FixedRecvByteBufAllocator(1024*1024*1024));
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            pipeline.addLast(new GzipCodec());

                            //固定帧长解码器
                            pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
                            pipeline.addLast(new LengthFieldPrepender(4));
                            pipeline.addLast(new ChunkedWriteHandler());

                            //自定义协议编解码器ServerApplication
                            pipeline.addLast(new MessageCodec());
                            pipeline.addLast("ping", new IdleStateHandler(60, 20, 60 * 10, TimeUnit.SECONDS));
                            //pipeline.addLast(new IdleCheckHandler(60, 30, 0));
                            pipeline.addLast(new ExportDealHandler());
                        }
                    });
            return connect();
        }catch (Exception e){
            log.error("",e);
        }
        return false;
    }

    public boolean connect() {
        try{
            if(!running)
            {
                return false;
            }
            if(channel != null && channel.isActive())
            {
                return true;
            }

            future = bootstrap.connect(serverHost, serverPort).sync();
            if (future.isSuccess()) {
                channel = future.channel();

                TransferMessageDto csNioMessage = new TransferMessageDto();
                csNioMessage.getConfig().setAppId(applicationName);
                csNioMessage.getConfig().setSessionId(SocketManager.appSessionId);
                csNioMessage.getConfig().setId(UUID.randomUUID().toString());
                csNioMessage.setType(ExportMessageTypeEnum.server_connect.code);

                channel.writeAndFlush(csNioMessage);
                log.info("connect server  成功---------");
                return true;
            }
        }
       catch (Exception e)
       {
           log.error("",e);
       }
        return false;
    }

    public void sendMessage(TransferMessageDto po)
    {
        channel.writeAndFlush(po);
    }

    @Override
    public void destroy()  {
        running = false;
        if(channel != null && channel.isActive())
        {
            channel.close();
        }

        if(eventLoopGroup != null)
        {
            eventLoopGroup.shutdownGracefully();
        }
    }
}
